注意:所有文章除特别说明外,转载请注明出处.
第八章 Java中的并发工具类
[TOC]
CountDownLatch、CyclicBarrier和Semaphore
工具类提供一种并发流程控制手段,Exchanger
工具类提供了在线程间交换数据的一种手段。
8.1 等待多线程完成的CountDownLatch
CountDownLatch 允许一个或多个线程等待其它线程完成操作。
需求:我们需要解析一个Excel里多个sheet的数据,此时可以考虑使用多线程,每个线程解析一个sheet里的数据,等到所有的sheet都解析完成之后,程序需要提示解析完成。
提示:join用于让当前线程等待join线程执行结束。其实现原理是不停的检查join线程是否存活,如果join线程存活则让当前线程永远等待。
注意:直到join线程中止后,线程的this.notifyAll()方法会被调用,调用notifyAll()方法是在JVM里实现的。
CountDownLatch 的构造函数接收一个int类型的参数作为计数器,如果想等待N个点完成,就传入N。
当调用CountDownLatch的countDown方法时,N就会减1,CountDownLatch的await()方法
会阻塞当前线程,直到N变为0。
await() 阻塞当前线程
如果有某个解析sheet的线程处理得比较慢,我们不可能让主线程一直等待,所以可以使用另外一个带指定时间的await()方法,这个方法等待特定时间之后就会不再阻塞当前线程。join也有类似方法。
await(long time, TimeUnit unit);//在特定时间之后就不会阻塞当前线程
8.2 同步屏障 CyclicBarrier
CyclicBarrier 表可循环使用的屏障。其做的事情是,让一组线程到达一个屏障(同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续运行。
8.2.1 CyclicBarrier简介
CyclicBarrier 的构造方法是 CyclicBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程调用await()方法告诉 CyclicBarrier 我已经到达屏障,然后当前线程被阻塞
。
CyclicBarrier(int parties);//参数表示屏障拦截的线程数量
8.2.2 CyclicBarrier 应用场景
CyclicBarrier 可用于多线程计算数据,最后合并计算结果的场景。
8.2.3 CyclicBarrier 和 CountDownLatch 的区别
CountDownLatch 的计数器只能使用一次,而 CyclicBarrier 的计数器可以使用reset()方法重置。
8.3 控制并发线程数的Semaphore
Semaphore (信号量)是用来控制同时访问特定资源的线程数量,通过协调各个线程,以保证合理的使用公共资源。
信号量可以指定多个线程同时访问某一个资源。提供构造函数:
1. public Semaphore(int permits);
2. public Semaphore(int permits, boolean fair);//fair指是否是公平锁
在构造信号量对象时应该指定信号量的准入数,即能够同时申请多少个许可。当每个线程每次只申请一个许可时,这就相当于指定了同时有多少个线程可以访问某一个资源。
1. public void acquire();
2. public void acquireUninterruptibly();//不响应中断
3. public boolean tryAcquire();//获取一个许可
4. public boolean tryAcquire(long timeout, TimeUnit unit);
5. public void release();
8.3.1 应用场景
Semaphore 可以用作流量控制,特别是公用资源有限的应用场景。
8.3.2 其它方法
1. int availablePermits() 返回此信号量当前可用的许可证数量
2. int getQueueLength() 返回正在等待获取许可证的线程数
3. boolean hasQueueThreads() 是否有线程正在等待获取许可证
4. void reducePermits(int reduction) 减少reduction个许可证
5. Collection getQueuedThread() 返回所有等待获取许可证的线程集合
8.4 线程间交换数据的Exchanger
Exchanger 是一个用于线程间协作的工具类。Exchanger用于进行线程间的数据交换。它提供一个同步点,在这个同步点,两线程可以交换彼此的数据。
如果一个线程先执行exchange()方法,它会一直等待第二个线程也执行exchange()方法,当两个线程都到达同步点时,这两个线程可以交换数据,将本线程生产出来的数据传递给对方。
8.5 线程阻塞工具类 LockSupport
线程阻塞工具类 LockSupport 是一个实用的工具类,可以在线程任意位置让线程阻塞。与Thread.suspend()方法比较,弥补了resume()方法发生导致线程无法继续执行的情况。
线程阻塞工具类 LockSupport 的静态方法 park() 方法阻塞当前线程,类似的还有 parkNanos() | parkUntil()等方法,其实现了一个限时等待。